#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "pwext.hpp"
#include <sys/time.h>

void ex05aa()
{
// [[ex05aa]]
	printf("Emergency exit!\n");
	_exit(1);
// END
}

void ex05ab()
{
// [[ex05ab]]
	printf("Emergency exit!\n");
	fflush(stdout);
	_exit(1);
// END
}

struct Request
{
	bool isValid()
	{
		return false;
	}
	void handle()
	{ }
};
Request get_next_request()
{
	return Request();
}

void ex05ac()
{
// [[ex05ac]]
// DEBUG descr The typical logic of the data handling threads.
bool exit_flag = false;
// ...
while(!exit_flag) {
	Request r = get_next_request();

	if (exit_flag)
		break;
	if (!r.isValid())
		continue;

	r.handle();
}
// END
}

int atomic_read(int &var)
{
	return var;
}
void ex05ad()
{
int exit_flag = 0;
// [[ex05ad]]
// DEBUG descr The reliable check of the exit flag.
while(!atomic_read(exit_flag)) {
	// ...
	if (atomic_read(exit_flag))
		break;
	// ...
}
// END
}

// [[ex05af]]
// DEBUG descr A thread performing an interruptible timeout.
class worker : public pw::pwthread
{
public:
	worker() : 
		exit_flag_(false)
	{ }
	// ...
	void *execute()
	{
		while(!get_exit_flag()) {
			Request r = get_next_request();

			if (get_exit_flag())
				break;
			if (!r.isValid())
				continue;

			// ... handle the request until need to sleep...
			if (mysleep(1000) != ETIMEDOUT)
				break; // it means, the exit was signaled
			// ... continue handling the request
		}
		return 0;
	}

	void stop()
	{
		{
			pw::lockmutex lm(exit_mutex_);
			exit_flag_ = true;
		}
		exit_event_.signal();
	}

	// will return 0 if exit was signaled, ETIMEDOUT
	// otherwise
	int mysleep(int milliseconds)
	{
		return exit_event_.msecwait(milliseconds);
	}

protected:
	bool get_exit_flag()
	{
		pw::lockmutex lm(exit_mutex_);
		return exit_flag_;
	}

	bool exit_flag_;
	pw::pmutex exit_mutex_;
	pw::event exit_event_;
	// ...
};
// END

// DEBUG {
int main()
{
	pw::event ev;
	ev.msecwait(100);
	return 0;
}
// DEBUG }
